home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Tool Chest / Testing & Debugging / Debuggers & dcmds / MacsBug 6.6 / Building dcmds / C Samples / DcmdShell.c next >
Encoding:
Text File  |  1999-10-20  |  9.0 KB  |  354 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        DcmdShell.c
  3.  
  4.     Contains:    This is the DcmdShell dcmd. This shell gives you a good start
  5.                 for a new Dcmd with a command line parser.
  6.  
  7.     Version:    1.0
  8.  
  9.     Written by:    Jim Luther
  10.  
  11.     Copyright:    © 1998-1999 by Apple Computer, Inc., All Rights Reserved.
  12.  
  13.     File Ownership:
  14.  
  15.         DRI:                Jim Luther
  16.  
  17.         Other Contact:        Dave Lyons or Jim Murphy
  18.  
  19.         Technology:            MacsBug Dcmds
  20.  
  21.     Writers:
  22.  
  23.         (JM3)    Jim Murphy
  24.         (JL)    Jim Luther
  25.  
  26.     Change History (most recent first):
  27.  
  28.          <2>    10/12/99    JM3        Added some unsigneds to make CodeWarrior builds happy.
  29.          <1>    10/11/99    JL        first checked in
  30.          <0>    10/15/98    JL        New today.
  31.  
  32.     To do:
  33.  
  34. */
  35.  
  36. //*******************************************************************************************************
  37.  
  38. #include <MacTypes.h>
  39. #include <StringCompare.h>
  40.  
  41. #include "dcmd.h"
  42. #include "put.h"
  43.  
  44. //*******************************************************************************************************
  45. //
  46. //    Constants and defines
  47. //
  48.  
  49. // The Dcmd's version number
  50. #define    kDcmdVersionNumber                                                            \
  51. {                                                                                    \
  52.     0x01,        /* 1st part of version number in BCD */                                \
  53.     0x00,        /* 2nd & 3rd part of version number share a byte */                 \
  54.     betaStage,    /* stage code:  developStage, alphaStage, betaStage, finalStage */     \
  55.     0x01        /* revision level of non-released version */                         \
  56. }
  57.  
  58. // The Dcmd's usage string (displayed by "DCMD DcmdShell" or by "? dcmds" or "help dcmds")
  59. #define    kDcmdUsageStr "\p[expression1 [expression2]] [-X] [-Y value] [-Z ON|OFF]"
  60.  
  61. // the Dcmd's error prefix string
  62. #define kDcmdErrPrefixStr "\pDcmdShell -  Error: "
  63.  
  64. // The maximum number of numeric expressions to parse from command line
  65. enum
  66. {
  67.     kMaxExpressions        = 2                // maximum number of expressions to parse from command line
  68. };
  69.  
  70. // StringsEqual - a case-insensitive, diacritical-sensitive string compare that's safe to
  71. // call at interrupt time that the parser uses for comparing parameter strings
  72. #define    StringsEqual(p1, p2)    EqualString(p1, p2, false, true)
  73.  
  74.  
  75. //*******************************************************************************************************
  76. //
  77. //    Globals
  78. //
  79.  
  80. static const unsigned char    gUsageStr[]            = kDcmdUsageStr;
  81.  
  82. static const unsigned char    gDcmdErrPrefixStr[]    = kDcmdErrPrefixStr;
  83.  
  84. static NumVersionVariant    gDcmdVersionNumber    = kDcmdVersionNumber;
  85.  
  86. //*******************************************************************************************************
  87. //
  88. //    Prototypes
  89. //
  90.  
  91. Boolean ParseParameters(UInt32 *expressionCount, UInt32 *expressions,
  92.                         Boolean *optionX, UInt32 *optionY, Boolean *optionZ);
  93.  
  94. pascal void DcmdCore(dcmdBlockPtr paramPtr);
  95.  
  96. pascal void CommandEntry(dcmdBlockPtr paramPtr);
  97.  
  98. //*******************************************************************************************************
  99. //
  100. //    ParseParameters
  101. //
  102. //    Scan through the entire command line to validate all the parameters.
  103. //    Returns true if the line parsed, false if it didn’t.
  104. //
  105. //    Command line syntax:
  106. //        DcmdShell [expression1 [expression2]] [-X] [-Y value] [-Z ON|OFF]
  107. //
  108. Boolean ParseParameters(UInt32 *expressionCount, UInt32 *expressions,
  109.                         Boolean *optionX, UInt32 *optionY, Boolean *optionZ)
  110. {
  111.     Boolean    parseOK;
  112.     short    position;
  113.     short    delimiter;
  114.     Str255    parameterStr;
  115.     Boolean    okExpression;
  116.     long    value;
  117.     UInt32    i;
  118.     
  119.     // Default settings for parameters
  120.     *expressionCount = 0;
  121.     for ( i = 0; i < kMaxExpressions; ++i )
  122.     {
  123.         expressions[i] = 0;
  124.     }
  125.     *optionX = false;
  126.     *optionY = 0;
  127.     *optionZ = false;
  128.     
  129.     // The parser first looks for string parameters.
  130.     // If the current parameter doesn't match any strings, then it is evaluated as an expression.
  131.     // By getting string parameters first, we can ensure that an dash option like "-A" is not seen as the value #-10.
  132.     parseOK = true;
  133.     do
  134.     {
  135.         position = dcmdGetPosition();    // Save current position in case we need to back up and try again as an expression
  136.         delimiter = dcmdGetNextParameter(parameterStr);    // Get the next parameter (if any) and the delimiter
  137.         if ( parameterStr[0] != 0 )
  138.         {
  139.             // Is it a '-' or a string parameter?
  140.             if ( StringsEqual(parameterStr, "\p-X") )
  141.             {
  142.                 // -X has no additional parameters
  143.                 
  144.                 // change the setting to the non-default value
  145.                 *optionX = !*optionX;
  146.             }
  147.             else if ( StringsEqual(parameterStr, "\p-Y") )
  148.             {
  149.                 // -Y has a expression parameter
  150.                 
  151.                 delimiter = dcmdGetNextExpression(&value, &okExpression);
  152.                 if (okExpression)
  153.                 {
  154.                     // return the expression passed for the -Y option
  155.                     *optionY = value;
  156.                 }
  157.                 else
  158.                 {
  159.                     // The expression was bad
  160.                     PutPStr(gDcmdErrPrefixStr);
  161.                     PutPStr("\p-Y expression was invalid");
  162.                     PutLine();
  163.                     parseOK = false;
  164.                 }
  165.             }
  166.             else if ( StringsEqual(parameterStr, "\p-Z") )
  167.             {
  168.                 // -Z has a string parameter
  169.                 
  170.                 delimiter = dcmdGetNextParameter(parameterStr);
  171.                 if ( StringsEqual(parameterStr, "\pON") )
  172.                 {
  173.                     *optionZ = true;
  174.                 }
  175.                 else if ( StringsEqual(parameterStr, "\pOFF") )
  176.                 {
  177.                     *optionZ = false;
  178.                 }
  179.                 else
  180.                 {
  181.                     // It wasn't a parameter we expected
  182.                     PutPStr(gDcmdErrPrefixStr);
  183.                     PutPStr("\p-Z parameter was invalid");
  184.                     PutLine();
  185.                     parseOK = false;
  186.                 }
  187.             }
  188.             else
  189.             {
  190.                 // Restore position if parameter not handled as string
  191.                 dcmdSetPosition(position);
  192.                 
  193.                 // and then try it as an expression
  194.                 delimiter = dcmdGetNextExpression(&value, &okExpression);
  195.                 if (okExpression)
  196.                 {
  197.                     // Return the expression if we haven't reached the maximum
  198.                     if ( *expressionCount < kMaxExpressions )
  199.                     {
  200.                         expressions[*expressionCount] = value;
  201.                         ++(*expressionCount);
  202.                     }
  203.                     else
  204.                     {
  205.                         // Too many expression parameters
  206.                         PutPStr(gDcmdErrPrefixStr);
  207.                         PutPStr("\pToo many expression parameters");
  208.                         PutLine();
  209.                         parseOK = false;
  210.                     }
  211.                 }
  212.                 else
  213.                 {
  214.                     // Bad comand line
  215.                     PutPStr(gDcmdErrPrefixStr);
  216.                     PutPStr("\pParameter could not be parsed");
  217.                     PutLine();
  218.                     parseOK = false;
  219.                 }
  220.             }
  221.         }
  222.  
  223.     } while ( (delimiter != 0x0d) && parseOK ); // look until the end of the line or until there's a problem
  224.     
  225.     if ( !parseOK )
  226.     {
  227.         // Burn the rest of the command line so MacsBug won't complain
  228.         // that "Command did not use all parameters"
  229.         do
  230.         {
  231.             delimiter = dcmdGetNextParameter(parameterStr);
  232.         } while ( delimiter != 0x0d );
  233.     }
  234.     
  235.     return ( parseOK );
  236.  
  237. } // ParseParameters
  238.  
  239.  
  240. //*******************************************************************************************************
  241. //
  242. //    DcmdCore
  243. //
  244. //    The main "do it" code
  245. //
  246. pascal void DcmdCore(dcmdBlockPtr paramPtr)
  247. {
  248.     // This sample doesn't use the dcmdBlockPtr parameter, but go look at all the cool stuff
  249.     // your Dcmd is passed (dcmd.h).
  250.     //
  251.     // In particular, if your Dcmd is going to do any time-comsuming tasks (like displaying large
  252.     // amounts of information) and you want the user to be able to abort, your Dcmd should watch
  253.     // the "aborted" field and exit if it changes to TRUE.
  254.     #pragma unused(paramPtr)
  255.     
  256.     UInt32        expressionCount;
  257.     UInt32        expressions[kMaxExpressions];
  258.     Boolean        optionX;
  259.     UInt32        optionY;
  260.     Boolean        optionZ;
  261.     UInt32        i;
  262.     
  263.     // Get command line parameters (if any)
  264.     if ( ParseParameters(&expressionCount, expressions, &optionX, &optionY, &optionZ) == true )
  265.     {
  266.         PutPStr("\pDcmdShell:");
  267.         PutLine();
  268.         
  269.         // Display the parsed parameters
  270.         
  271.         // Display the expression parameters (if any)
  272.         if ( expressionCount == 0 )
  273.         {
  274.             PutPStr("\pNo expression parameters");
  275.             PutLine();
  276.         }
  277.         else
  278.         {
  279.             for ( i = 0; i < expressionCount; ++i )
  280.             {
  281.                 PutPStr("\pExpression ");
  282.                 PutUDec(i + 1);
  283.                 PutPStr("\p = $");
  284.                 PutUHexZ(expressions[i], 8);
  285.                 PutLine();
  286.             }
  287.         }
  288.         
  289.         // Display the string parameters
  290.         PutPStr("\pOptionX = ");
  291.         PutPStr(optionX ? "\pTRUE" : "\pFALSE");
  292.         PutLine();
  293.         
  294.         PutPStr("\pOptionY = $");
  295.         PutUHexZ(optionY, 8);
  296.         PutLine();
  297.         
  298.         PutPStr("\pOptionZ = ");
  299.         PutPStr(optionZ ? "\pON" : "\pOFF");
  300.         PutLine();
  301.     }
  302. } // DcmdCore
  303.  
  304. //*******************************************************************************************************
  305. //
  306. //    CommandEntry
  307. //
  308. //    The main entry point for this dcmd
  309. //
  310. pascal void CommandEntry(dcmdBlockPtr paramPtr)
  311. {
  312.     switch ( paramPtr->request )
  313.     {
  314.         case dcmdInit:
  315.             // Initialize the Dcmd
  316.             // (called when MacsBug is loaded)
  317.             break;
  318.         
  319.         case dcmdDoIt:
  320.             // Normal Dcmd execution
  321.             // (called when MacsBug wants us to do our job)
  322.             dcmdSwapWorlds();
  323.             DcmdCore(paramPtr);
  324.             dcmdSwapWorlds();
  325.             break;
  326.         
  327.         case dcmdHelp:
  328.             // Display help for Dcmd
  329.             dcmdDrawLine("\pA sample dcmd shell");
  330.             break;
  331.         
  332.         case dcmdSecondaryInit:
  333.             // Second time to init after all System patches have been loaded
  334.             // (called just before extensions are executed)
  335.             break;
  336.         
  337.         case dcmdShutdown:
  338.             // Dcmd should remove or disable its patches (if any).
  339.             break;
  340.         
  341.         case dcmdGetInfo:
  342.             // Return Dcmd version and usage string
  343.             dcmdFillVersion(paramPtr, gDcmdVersionNumber.whole);
  344.             dcmdFillString(paramPtr, usageStr, gUsageStr);
  345.             break;
  346.         
  347.         default:
  348.             // Version 3 and later Dcmds must quietly ignore unrecognized requests
  349.             break;
  350.     }
  351. } // CommandEntry
  352.  
  353. //*******************************************************************************************************
  354.